#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "../../../include/callback_currying/portability/stdint.h"
#if defined(DEP_TEST_STORAGE_REQUIREMENT)
#include "DEP.h"
#endif

static int simple_function(void) { return 1212; }
typedef int (*function_t)(void);

int main(void) {

#define CODE_SIZE 86
/* assume suitable */

#if defined(DEP_TEST_STORAGE_STATIC)
    static unsigned char static_storage[CODE_SIZE] = {0};
    unsigned char* storage = static_storage;
    const char* storage_name = "static";
#elif defined(DEP_TEST_STORAGE_STACK)
    unsigned char stack_storage[CODE_SIZE] = {0};
    unsigned char* storage = stack_storage;
    const char* storage_name = "stack";
#elif defined(DEP_TEST_STORAGE_HEAP)
    unsigned char* storage = (unsigned char*)malloc(CODE_SIZE);
    const char* storage_name = "heap";
#elif defined(DEP_TEST_STORAGE_FREESTORE)
    unsigned char* storage = new unsigned char[CODE_SIZE];
    const char* storage_name = "free store";
#elif defined(DEP_TEST_STORAGE_REQUIREMENT)
    unsigned char* storage = AllocRWEMemory(CODE_SIZE);
    const char* storage_name = "readable writable and executable";
#else
#error unknown storage type
#endif

    function_t fn = (function_t)(uintptr_t)storage;
    int result = 0;


#ifndef __cplusplus
    printf("-------- C data execution prevention test --------\n");
#else
    printf("-------- C++ data execution prevention test --------\n");
#endif
    printf("storage=\"%s\"\n",storage_name);

    if (!storage) {
        printf("alloc memory failed\npress enter to exit\n");
        (void)getchar();
        return -1;
    }

    printf("\nabout to read machine code\n");
    printf("-------- to test read privilege of function body --------\n");
    /*
    function body has execution access right.
    what about read access right?

    if we want to execute a shell script, it must have read access right.
    the interpreter will "read" the script.

    function body must have read access right
       because CPU "read" the instruction before "execute" it,isn't it?
    */
    memcpy(storage,(const void*)(uintptr_t)simple_function,CODE_SIZE);
    printf("-------- test succeeded --------\n");

    printf("\nabout to execute machine code\n");
    printf("-------- to test data execution prevention --------\n");
    result = fn();
    printf("-------- test succeeded result=%d --------\n",result);

#if defined(DEP_TEST_STORAGE_STATIC)
#elif defined(DEP_TEST_STORAGE_STACK)
#elif defined(DEP_TEST_STORAGE_HEAP)
    free(storage);
#elif defined(DEP_TEST_STORAGE_FREESTORE)
    delete[] storage;
#elif defined(DEP_TEST_STORAGE_REQUIREMENT)
    FreeRWEMemory(storage);
#else
#error unknown storage type
#endif

    printf("\npress enter to exit\n");
    (void)getchar();
    return 0;
}
